//
//    Copyright (C) 2012  OinkStudio
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.


package com.marakana.obolo;

//Imports de Android
import java.util.Random;

import android.app.Activity;
import android.os.Bundle;
import android.graphics.Color;
import android.graphics.Point;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View.OnTouchListener;
import graphics.FinishDialog;
import graphics.OboloGraphicsView;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
// Imports de game
import game.Game;
import game.Obolo;
import game.Player;
import game.CPU;
import game.IAOboloHelp;

public class GameActivity extends Activity {
	private static Game game;
	private IAOboloHelp iaHelper;
	private LinearLayout[] deckPlayersLay;
	private TableLayout boardLay;
	private TextView[] txtPlayers;
	private OboloGraphicsView oboloPressed;
	private int heightRatio = 57;

	/** Called when the activity is first created. */
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// Crea la vista de Game
		setContentView(R.layout.game);
		
		// Captura de les variables que s'envien mitjan�ant un intent
		Bundle extras = getIntent().getExtras();
		int[] dimension = extras.getIntArray("dimension");
		String[] rules = extras.getStringArray("rules");
		Player user = (Player) extras.getSerializable("user");
		Player rival = (Player) extras.getSerializable("rival");
				
		// Controlar de que la dimensio s'hagi pasat correctament abans de crear
		// el game
		game = new Game(dimension[0], dimension[1], dimension[2]);
		
		// Afegir els components que necessita game per funcionar (Players y
		// Rules)
		game.setPlayers(rival, user);

		// Crea las normes per afegirlas a game
		game.setRules(rules);
		
		// Inicialitza les referencias als objectes del game.xml
		deckPlayersLay = new LinearLayout[2];
		deckPlayersLay[0] = (LinearLayout) findViewById(R.id.linLayDeckRival);
		deckPlayersLay[1] = (LinearLayout) findViewById(R.id.linLayDeckUser);
		txtPlayers = new TextView[2];
		txtPlayers[0] = (TextView) findViewById(R.id.txtRivalName);
		txtPlayers[1] = (TextView) findViewById(R.id.txtUserName);

		boardLay = (TableLayout) findViewById(R.id.tabLayBoard);

		// Dona format als graphics del joc segons les dimensions de la pantalla
		boundsViewsOnScreen();
		
		// Se li pasa un int que referencia als drawables per a que en mostri un
		// aleatoriament
		addDynamicBackground(new int[] { R.drawable.grave, R.drawable.train,
				R.drawable.dungeon });

		// Omple de obolos els decks dels jugadors
		fillDeck(deckPlayersLay[Game.RIVAL], game.getPlayerDeck(Game.RIVAL));
		fillDeck(deckPlayersLay[Game.USER], game.getPlayerDeck(Game.USER));
		fillBoard(boardLay, game.getBoard());

		// Afegeix les dades dels jugadors
		txtPlayers[Game.RIVAL].setText(game.getPlayerName(Game.RIVAL));
		txtPlayers[Game.USER].setText(game.getPlayerName(Game.USER));

		// Assigna el torn
		updateTurn(game.getTurn());

		// Comproba si hi ha alguna m�quina com a jugador i l'activa
		for (int i = 0; i < 2; i++) {
			if (!game.getPlayer(i).isHuman()) {
				disablePlayer(deckPlayersLay[i]);
				iaNextTurn();
			}
		}
		
	}

	private boolean hasTurn(LinearLayout deck) {
		if (deckPlayersLay[game.getTurn()] == deck)
			return true;
		else
			return false;
	}

	private void updateTurn(int gameTurn) {
		if (gameTurn == Game.RIVAL) {
			txtPlayers[Game.RIVAL].setTextColor(Color.YELLOW);
			txtPlayers[Game.USER].setTextColor(Color.WHITE);
			if (game.getPlayer(Game.RIVAL).isHuman()) {
				// Activa el turno de rival
				enablePlayer(deckPlayersLay[Game.RIVAL]);
				// Desactiva el turno de user
				disablePlayer(deckPlayersLay[Game.USER]);
			}
		} else {

			txtPlayers[Game.USER].setTextColor(Color.YELLOW);
			txtPlayers[Game.RIVAL].setTextColor(Color.WHITE);
			if (game.getPlayer(Game.USER).isHuman()) {
				// Desactiva el turno rival
				disablePlayer(deckPlayersLay[Game.RIVAL]);
				// Activa el turno user
				enablePlayer(deckPlayersLay[Game.USER]);
			}
		}
	}

	private void enablePlayer(LinearLayout deckLay) {
		// Activa los obolos del deck del jugador
		for (int i = 0; i < deckLay.getChildCount(); i++) {
			deckLay.getChildAt(i).setEnabled(true);
		}
	}

	private void disablePlayer(LinearLayout deckLay) {
		// Desactiva los obolos del deck del jugador
		for (int i = 0; i < deckLay.getChildCount(); i++) {
			deckLay.getChildAt(i).setEnabled(false);
		}
	}

	private void fillDeck(LinearLayout deckLay, Obolo[] deck) {
		OboloGraphicsView obolo;

		for (int column = 0; column < deck.length; column++) {
			// Crea el oboloView
			obolo = new OboloGraphicsView(this, deck[column]);
			// Li dona la mida al obolo segons la llargada de la pantalla
			obolo.setBoundsHeight(heightRatio);
			// Li afegeix en el tag la posicio que ocupa el obolo en el deck
			obolo.setTag(column);

			// Afegeix el event al obolo del deck
			obolo.setOnTouchListener(new OnTouchListener() {

				@Override
				public boolean onTouch(View v, MotionEvent event) {
					if (hasTurn((LinearLayout) v.getParent())) {
						if (oboloPressed != null)
							oboloPressed.setBackgroundColor(Color.TRANSPARENT);
						oboloPressed = (OboloGraphicsView) v;
						oboloPressed.setBackgroundColor(Color.YELLOW);
						return true;
					} else
						return false;
				}
			});
			// Afegeix obolos en el deck
			deckLay.addView(obolo);
		}
	}

	private void fillBoard(TableLayout boardLay, Obolo[][] board) {
		this.boardLay = boardLay;
		OboloGraphicsView obolo;

		for (int row = 0; row < board.length; row++) {
			TableRow boardRow = new TableRow(this);
			// Centra el taulell a la pantalla
			boardRow.setGravity(Gravity.CENTER);
			// Afegeix obolos a cada fila
			for (int column = 0; column < board[0].length; column++) {
				// Crea el oboloView
				obolo = new OboloGraphicsView(this, board[row][column]);
				// Li dona la mida al obolo segons la llargada de la pantalla
				obolo.setBoundsHeight(heightRatio);
				// Li afegeix en el tag la posicio que ocupa el obolo en el
				// taulell
				obolo.setTag(new Point(row, column));
				// Afegeix el event dels obolos dins el taulell
				obolo.setOnTouchListener(new OnTouchListener() {

					@Override
					public boolean onTouch(View v, MotionEvent event) {
						if (oboloPressed != null) {
							playObolo((OboloGraphicsView) v);
							return true;
						} else
							return false;
					}
				});
				boardRow.addView(obolo);
			}
			// Afegeix les files per montar el taulell
			boardLay.addView(boardRow);
		}
	}

	private void playObolo(OboloGraphicsView oboloBoard) {
		Point boardPoint = null;
		try {
			boardPoint = (Point) oboloBoard.getTag();
			game.putObolo(boardPoint.x, boardPoint.y, oboloPressed.getObolo());
			
			oboloBoard.setObolo(game.getBoard()[boardPoint.x][boardPoint.y]);
			// Actualitza el estat del Obolo triat en el deck
			oboloPressed.setObolo(null);
			// Repinta el estat de la partida
			redraw(boardPoint);

			// Mostra la norma activada
			/*
			 * Toast.makeText(this, "", Toast.LENGTH_LONG) .show();
			 */

			// Comproba si s'ha acabat la partida
			if (game.isFinish()) {
				// Acaba la partida
				//Es mira qui es el perdedor i qui el guanyador
				Player winner = game.whoWin();
				if(winner != null){
					if(game.whoWin().equals(game.getPlayer(0))){
						finishGame(game.getPlayer(0), game.getPlayer(1));
					}
					else{
						finishGame(game.getPlayer(1), game.getPlayer(0));
					}
				}
				else{
					finishGame(null,null);
				}
				
				
			} else {
				oboloPressed.setOnTouchListener(null);
				oboloPressed = null;
				updateTurn(game.getTurn());
				// Comproba si ha de tirar la IA
				if (!game.getPlayer(game.getTurn()).isHuman())
					iaNextTurn();
			}
		} catch (IllegalArgumentException e) {

		}
	}

	protected void finishGame(Player winner, Player looser) {
		// Crea un Dialog
		FinishDialog finishDialog = null;
		
		if (winner == null)
			// Mostra el empat
			finishDialog = new FinishDialog(this);
		else{
			// Mostra el guanyador de la partida i deixa triar el premi
				finishDialog = new FinishDialog(this, winner, looser);
		}			
		
		finishDialog.setOwnerActivity(this);
		finishDialog.setCancelable(true);
		finishDialog.setCanceledOnTouchOutside(true);		
		finishDialog.show();
		//finish();
	}

	// Metode que fa tirar a la m�quina
	private void iaNextTurn() {
		iaHelper = ((CPU) game.getPlayer(game.getTurn())).bestOption(game);
		// Selecciona el obolo del deck que vol jugar
		for (int i = 0; i < game.getPlayerDeck(game.getTurn()).length; i++) {
			if (iaHelper.obolo == (game.getPlayerDeck(game.getTurn())[i])) {
				oboloPressed = (OboloGraphicsView) deckPlayersLay[game
						.getTurn()].getChildAt(i);
				oboloPressed.setObolo(game.getPlayer(game.getTurn())
						.getObolo(i));
			}
		}
		// Selecciona la posicio del taulell a on jugara el Obolo
		for (int row = 0; row < boardLay.getChildCount(); row++) {
			if (iaHelper.row == row) {
				TableRow rowLay = (TableRow) boardLay.getChildAt(row);
				for (int column = 0; column < rowLay.getChildCount(); column++) {
					if (iaHelper.column == column)
						playObolo((OboloGraphicsView) rowLay.getChildAt(column));
				}
			}
		}
	}

	private void redraw(Point boardPoint) {
		for (int row = 0; row < boardLay.getChildCount(); row++) {
			TableRow rowLay = (TableRow) boardLay.getChildAt(row);
			for (int column = 0; column < rowLay.getChildCount(); column++) {
				rowLay.getChildAt(column).invalidate();
			}
		}
		oboloPressed.invalidate();
		oboloPressed.setBackgroundColor(Color.TRANSPARENT);
	}
	
	protected void boundsViewsOnScreen() {
		// Calcula el heightRatio per donar format a tots els views adequats a
		// la pantalla
		DisplayMetrics metrics = new DisplayMetrics();
		// Recupera el sistema metrico de la pantalla
		getWindowManager().getDefaultDisplay().getMetrics(metrics);
		heightRatio = (int) (metrics.heightPixels / (4 + game.getRowNumber()));
		
		// Dona Format als Views y els dimensiona segons les dimensions de la
		// pantalla
		boardLay.setPadding(5, heightRatio / 2, 5, heightRatio / 4);
		for (TextView txtView : txtPlayers) {
			txtView.setTextSize(heightRatio / 4);
			txtView.setPadding(2, 2, 2, 2);
		}
	}
	
	protected void addDynamicBackground(int[] backgrounds) {
		Random rand = new Random();
		// Instancia el Layout general de la pantalla per donarli background
		LinearLayout mainLay = (LinearLayout) boardLay.getParent();

		// Afegeix un background aleatoriament dels de la llista
		mainLay.setBackgroundResource(backgrounds[rand
				.nextInt(backgrounds.length)]);
	}
	
}
